﻿//---------------------------------------------------------------------------------
// Copyright 2011 Microsoft Corporation
// Licensed under the Microsoft Public License (MS-PL) (the "License"); 
// You may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.opensource.org/licenses/ms-pl.html
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR 
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
// INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR 
// CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
// MERCHANTABLITY OR NON-INFRINGEMENT. 
// See the Microsoft Public License (MS-PL) for the specific language governing 
// permissions and limitations under the License.
//---------------------------------------------------------------------------------
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Net;
using System.Web;

namespace Microsoft.Telco.WindowsLive
{

	public static class WrapProtocolHelper
	{
		// Methods
		private static string BuildAccessTokenRequestBody(AppInformation appInfo)
		{
			string format = "wrap_client_id={0}&wrap_client_secret={1}&wrap_callback={2}&wrap_verification_code={3}";
			string callbackUrl = appInfo.CallbackUrl;
			if (!string.IsNullOrEmpty(appInfo.SessionId))
			{
				Uri uri = new Uri(callbackUrl);
				callbackUrl = uri.GetComponents(UriComponents.Path | UriComponents.SchemeAndServer | UriComponents.UserInfo, UriFormat.Unescaped).TrimEnd(new char[] { '/' });
			}
			return string.Format(CultureInfo.InvariantCulture, format, new object[] { HttpUtility.UrlEncode(appInfo.ClientId), HttpUtility.UrlEncode(appInfo.ClientSecret), HttpUtility.UrlEncode(callbackUrl), appInfo.AuthInfo.ClientVerifier });
		}

		private static string BuildRefreshTokenRequestBody(AppInformation appInfo)
		{
			string format = "wrap_refresh_token={0}&wrap_client_id={1}&wrap_client_secret={2}";
			return string.Format(CultureInfo.InvariantCulture, format, new object[] { appInfo.AuthInfo.RefreshToken, appInfo.ClientId, appInfo.ClientSecret });
		}

		public static bool ParseAccessToken(string token, AppAuthentication authInfo, DateTime requestTime)
		{
			string[] strArray = token.Split(AuthConstants.Wrap.ParameterSeparator);
			if ((strArray != null) && (strArray.Length > 0))
			{
				foreach (string str in strArray)
				{
					if (str.StartsWith("wrap_error_reason=", StringComparison.Ordinal))
					{
						authInfo.Error = new AuthorizationException(HttpUtility.UrlDecode(str.Substring("wrap_error_reason=".Length)));
						break;
					}
					if (str.StartsWith("wrap_access_token=", StringComparison.Ordinal))
					{
						authInfo.AccessToken = HttpUtility.UrlDecode(str.Substring("wrap_access_token=".Length));
						if (!string.IsNullOrEmpty(authInfo.AccessToken))
						{
							goto Label_017C;
						}
						authInfo.Error = new AuthorizationException(StringResource.NoAccessTokenReturned);
						break;
					}
					if (str.StartsWith("wrap_refresh_token=", StringComparison.Ordinal))
					{
						authInfo.RefreshToken = str.Substring("wrap_refresh_token=".Length);
						if (!string.IsNullOrEmpty(authInfo.RefreshToken))
						{
							goto Label_017C;
						}
						authInfo.Error = new AuthorizationException(StringResource.NoRefreshTokenReturned);
						break;
					}
					if (str.StartsWith("wrap_access_token_expires_in=", StringComparison.Ordinal))
					{
						long num;
						authInfo.Expiry = string.Empty;
						if (long.TryParse(str.Substring("wrap_access_token_expires_in=".Length), out num))
						{
							TimeSpan span = (TimeSpan)(requestTime.AddSeconds((double)num) - AuthConstants.Wrap.BaseDateTime);
							authInfo.Expiry = ((long)span.TotalSeconds).ToString();
						}
					}
					else if (str.StartsWith("uid=", StringComparison.Ordinal))
					{
						authInfo.UserId = str.Substring("uid=".Length);
					}
				Label_017C: ;
				}
			}
			return (!string.IsNullOrEmpty(authInfo.AccessToken) && !string.IsNullOrEmpty(authInfo.RefreshToken));
		}

		public static void ParseCallbackQuery(NameValueCollection parameters, out string verifier, out string clientState, out string scope, out string error)
		{

			error = null;
			verifier = parameters["wrap_verification_code"];
			clientState = parameters["wrap_client_state"];
			
			scope = parameters["exp"];
			if (!string.IsNullOrEmpty(scope))
			{
				scope = HttpUtility.UrlDecode(scope).Replace(";", ",");
			}

			string errorCode = parameters["error_code"];
			string wrapErrorReason = parameters["wrap_error_reason"];

			if (!string.IsNullOrEmpty(errorCode) || !string.IsNullOrEmpty(wrapErrorReason))
				error = string.Format("{0} {1}", errorCode, wrapErrorReason);

		}

		internal static string ParseErrorResponseBody(string body)
		{
			string str = string.Empty;
			string str2 = string.Empty;
			string str3 = string.Empty;
			string str4 = string.Empty;
			string[] strArray = body.Split(new char[] { '&' });
			if (strArray.Length > 0)
			{
				foreach (string str5 in strArray)
				{
					if (str5.StartsWith("error_code="))
					{
						str2 = HttpUtility.UrlDecode(str5.Substring("error_code=".Length));
					}
					else if (str5.StartsWith("wrap_error_reason="))
					{
						str3 = HttpUtility.UrlDecode(str5.Substring("wrap_error_reason=".Length));
					}
				}
			}
			if (string.IsNullOrEmpty(str2) && string.IsNullOrEmpty(str3))
			{
				return str;
			}
			return (str2 + " " + str3 + " " + str4);
		}

		internal static Collection<Offer> ParseOffers(string grantedOffers)
		{
			Collection<Offer> collection = new Collection<Offer>();
			if (!string.IsNullOrEmpty(grantedOffers))
			{
				foreach (string str in grantedOffers.Split(new char[] { AuthConstants.Wrap.OfferSeparator[0] }))
				{
					collection.Add(new Offer(str));
				}
			}
			return collection;
		}

		private static bool ProcessAccessTokenResponse(HttpWebRequest request, HttpWebResponse response, AppAuthentication authInfo, DateTime requestTime)
		{
			if (response != null)
			{
				using (StreamReader reader = new StreamReader(response.GetResponseStream()))
				{
					return ParseAccessToken(reader.ReadToEnd(), authInfo, requestTime);
				}
			}
			authInfo.Error = new AuthorizationException(string.Format(CultureInfo.CurrentCulture, StringResource.NullResponseReceived, new object[] { request.RequestUri.ToString() }));
			return false;
		}

		internal static Exception ProcessGetTokenWebException(WebException webExp)
		{
			string message = webExp.Message;
			HttpWebResponse response = webExp.Response as HttpWebResponse;
			if (response != null)
			{
				Stream responseStream = response.GetResponseStream();
				if (responseStream != null)
				{
					using (StreamReader reader = new StreamReader(responseStream))
					{
						string str2 = reader.ReadToEnd();
						if (!string.IsNullOrEmpty(str2))
						{
							message = ParseErrorResponseBody(str2);
						}
					}
				}
			}
			return new AuthorizationException(message, webExp);
		}

		internal static bool RefreshAccessToken(AppInformation appInfo)
		{
			if (appInfo == null)
			{
				throw new ArgumentNullException("appInfo");
			}
			if (string.IsNullOrEmpty(appInfo.AuthInfo.RefreshToken))
			{
				appInfo.AuthInfo.Error = new ArgumentException(StringResource.RefreshTokenInvalid);
				return false;
			}
			bool flag = false;
			appInfo.AuthInfo.AccessToken = null;
			appInfo.AuthInfo.Expiry = null;
			try
			{
				Uri requestUri = new Uri(appInfo.ConsentRoot, "RefreshToken.aspx");
				HttpWebRequest request = WebRequest.Create(requestUri) as HttpWebRequest;
				request.Method = "POST";
				request.ContentType = "application/x-www-form-urlencoded";
				using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
				{
					writer.Write(BuildRefreshTokenRequestBody(appInfo));
					writer.Close();
					DateTime now = DateTime.Now;
					HttpWebResponse response = request.GetResponse() as HttpWebResponse;
					if (response != null)
					{
						using (StreamReader reader = new StreamReader(response.GetResponseStream()))
						{
							return ParseAccessToken(reader.ReadToEnd(), appInfo.AuthInfo, now);
						}
					}
					appInfo.AuthInfo.Error = new AuthorizationException(string.Format(CultureInfo.CurrentCulture, StringResource.NullResponseReceived, new object[] { request.RequestUri.ToString() }));
					return flag;
				}
			}
			catch (WebException exception)
			{
				appInfo.AuthInfo.Error = ProcessGetTokenWebException(exception);
			}
			catch (Exception exception2)
			{
				appInfo.AuthInfo.Error = exception2;
			}
			return flag;
		}

		public static bool RequestAccessToken(AppInformation appInfo)
		{
			if (appInfo == null)
			{
				throw new ArgumentNullException("appInfo");
			}
			bool flag = false;
			try
			{
				Uri requestUri = new Uri(appInfo.ConsentRoot, "AccessToken.aspx");
				HttpWebRequest request = WebRequest.Create(requestUri) as HttpWebRequest;
				request.Method = "POST";
				request.ContentType = "application/x-www-form-urlencoded";
				using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
				{
					writer.Write(BuildAccessTokenRequestBody(appInfo));
					writer.Close();
					DateTime now = DateTime.Now;
					HttpWebResponse response = request.GetResponse() as HttpWebResponse;
					if (response != null)
					{
						using (StreamReader reader = new StreamReader(response.GetResponseStream()))
						{
							flag = ParseAccessToken(reader.ReadToEnd(), appInfo.AuthInfo, now);
						}
					}
					return flag;
				}
			}
			catch (WebException exception)
			{
				appInfo.AuthInfo.Error = ProcessGetTokenWebException(exception);
			}
			catch (Exception exception2)
			{
				appInfo.AuthInfo.Error = exception2;
			}
			return flag;
		}

	}

}
